package cs343;

import java.io.File;

import java.io.FileWriter;
import java.io.IOException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import cs343.Score;

/**
 * <p>
 * Title: CS 343 Project: Pong
 * </p>
 * <p>
 * Description: CS 343 Project 
 * This class contains an ArrayList of Scores that is used when
 * displaying the highScores in the menu and is used to store
 * all of the scores in the pong_scores file
 * </p>
 * 
 * @author Jenny Windsperger, Stirling Pankow, Will Prew, Shane O'Malley-Potting
 * @email jennifer.windsperger@my.uwrf.edu, stirling.pankow@my.uwrf.edu,
 *        william.prew@my.uwrf.edu, shane.omalley-potting@my.uwrf.edu
 * @date December 1st 2011
 */

public class HighScores {
	private List<Score> highScores;
	final String INPUT_FILE = "src/pong_scores.xml";

	/**
	 * Default constructor that reads in the scores from the pong_scores file
	 * postcondition: List contains the scores from the file
	 * @throws XPathExpressionException 
	 */
	public HighScores() {
		try{
			this.highScores = getScores();
		}
		catch (Exception e){}
	}

	/**
	 * Method parses out all the scores from the XML file and saves them to a List<Score>
	 * Precondition: The file exists and has properly formated XML
	 * Postcondition: Returns a List<Score> with each <submission> represented as a Score object
	 */
	public List<Score> getScores(){
		File scores = new File(INPUT_FILE);
		Document doc = null;
		try {
            DocumentBuilder docbuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            doc = docbuilder.parse(scores);
        } catch (Exception e) {}
        XPath path = XPathFactory.newInstance().newXPath();
        NodeList l1 = null;
        NodeList l2 = null;
		try {
			l1 = (NodeList)(path.compile("//submission/score[1]/text()").evaluate(doc, XPathConstants.NODESET));
			l2 = (NodeList)(path.compile("//submission/alias[1]/text()").evaluate(doc, XPathConstants.NODESET));
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
        
		List<Score> scoresList = new ArrayList<Score>();
        for(int i = 0; i < l2.getLength(); i++){
        	scoresList.add(new Score(Integer.parseInt(l1.item(i).getNodeValue()), l2.item(i).getNodeValue()));
        }
        return scoresList;
	}
	/**
	 * Method that saves the newest score into the pong_scores file
	 * Preconditions: pong_scores is in the src folder Postcondition: the newest
	 * score is in the pong_scores file
	 */
	void writeScores(List<Score> scores) throws IOException {
		FileWriter output = new FileWriter(INPUT_FILE, false);
		String writeString = "<scores>\n";
		//Saves all the separate high scores in their XML tags
		for(Score s : scores){
			writeString += "<submission><score>" + s.getScore() + "</score><alias>" + s.getAlias().toUpperCase() + "</alias></submission>\n";
		}
		writeString += "</scores>";
		
		// write the score and the alias to the file
		output.write(writeString);
		output.close();
	}
	/**
	 * Method that sets up modified scores list
	 * Precondition: 
	 * Postcondition: the updated high scores list is sorted and written
	 */
	public void updateScores(Score score){
		if(highScores.size() < 10)
			highScores.add(score);
		else {
			highScores.remove(Collections.min(highScores));
			highScores.add(score);
		}
		//Sorts them which puts them in ascending order and reverses it so the highest is first
		Collections.sort(highScores);
		Collections.reverse(highScores);
		try{
			writeScores(highScores);
		}
		catch (IOException e){}
	}
/**
 * Method that checks to see if a score is a high score
 * Precondtion: 
 * Postcondition: returns if the score is larger than the lowest score
 */
	public boolean checkScore(int score){
		//If there aren't 10 scores or the score is higher than the lowest saved score
		if(highScores.size() < 10 || (Collections.min(highScores)).getScore() < score){
			return true;
		}
		else 
			return false;
	}


	/**
	 * toString method that calls the Score class's toString to get the alias
	 * and the scores
	 */
	public String toString() {
		String scores = "";
		for(Score s : getScores()){
			scores += s + "\n";
		}
		return scores;
	}


	/**
	 * Getter for highScores
	 */
	public List<Score> getHighScores() {
		return highScores;
	}


	/**
	 * Setter for highScores
	 * Postcondition: this.highScores = highScores
	 */
	public void setHighScores(List<Score> highScores) {
		this.highScores = highScores;
	}
}
